/**
 * Copyright  (c) 2009-2013 XLab,  Org. 
 * All  rights  reserved. 
 */
package org.xlab.baseframework.system;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.springframework.context.MessageSource;
import org.xlab.baseframework.domain.SystemCode;
import org.xlab.baseframework.domain.SystemParameter;
import org.xlab.baseframework.exception.SystemCodeNotFoundException;
import org.xlab.baseframework.exception.SystemParameterNotFoundException;
import org.xlab.baseframework.exception.SystemRuntimeException;

/**
 * 系统环境
 * 
 * @author MaKuBEX Email:makubexnet@gmail.com
 * @version 1.0.0 Sep 8, 2010
 * @since 1.0.0
 * 
 */
public class SystemRuntimeEnvironment implements Serializable {

	/**
	 * @serialField
	 */
	private static final long serialVersionUID = -3957097842153771919L;
	private static final Logger log = Logger
			.getLogger(SystemRuntimeEnvironment.class);

	/**
	 * <p>
	 * 从内存中根据代码类别获取系统代码
	 * </p>
	 * 
	 * @param category
	 *            代码类别
	 * @return 系统代码列表实例
	 * @throws SystemCodeNotFoundException
	 *             如果该类别在内存中没有任何记录
	 */
	public synchronized static List<SystemCode> findAllCodeByCategory(
			SystemCode category) throws SystemCodeNotFoundException {
		Collection<SystemCode> entries = systemCodes.values();
		List<SystemCode> result = new ArrayList<SystemCode>();
		for (SystemCode code : entries) {
			if (category != null && category.equals(code.getCategory()))
				result.add(code);
			else if (category == null && code.getCategory() == null)
				result.add(code);
		}
		if (result.isEmpty())
			throw new SystemCodeNotFoundException();
		return result;
	}

	/**
	 * 从内存中将对应的系统代码删除
	 * 
	 * @param code
	 *            系统代码
	 */
	public synchronized static void removeCode(String code) {
		if (systemCodes == null) {
			log.warn("System has not been initialized!");
		}
		SystemCode result = systemCodes.get(code);
		if (result == null) {
			log.warn("Can not find the system code [" + code + "] from cache!");
		} else {
			log.debug("Removing system code [" + code + "] description ["
					+ result.getDescription() + "] from cache.");
			systemCodes.remove(code);
		}
	}

	/**
	 * 从缓存中清除指定的系统参数
	 * 
	 * @param code
	 *            系统参数代码
	 */
	public synchronized static void removeParameter(String code) {
		if (systemParameters == null) {
			log.error("System has not been initialized!");
			throw new SystemRuntimeException("System has not been initialized!");
		}
		SystemParameter result = systemParameters.get(code);
		if (result == null) {
			log.warn("There is not any parameter named [" + code + "]");
		} else {
			systemParameters.remove(code);
			log.debug("System parameter [" + code
					+ "] has been removed from cache!");
		}
	}

	/**
	 * 更新/新增系统代码,若内存中已经存在该系统代码,则将更新该值,否则则将新代码放到内存中
	 * 
	 * @param code
	 *            系统代码
	 */
	public synchronized static void setCode(SystemCode code) {
		if (systemCodes == null) {
			log.warn("System has not been initialized!");
		}
		SystemCode result = systemCodes.get(code.getCode());
		if (result == null) {
			log.debug("Adding new system code [" + code.getCode()
					+ "] description [" + code.getDescription() + "]");
		} else {
			log.debug("Updating system code [" + code.getCode()
					+ "] from description [" + result.getDescription()
					+ "] to description [" + code.getDescription() + "].");
		}
		systemCodes.put(code.getCode(), code);
	}

	/**
	 * 更新/新增系统参数,若内存中已经存在该参数值,则将更新该值,否则则将新参数存放到内存中
	 * 
	 * @param parameter
	 *            系统参数
	 */
	public synchronized static void setParameter(SystemParameter parameter) {
		if (systemParameters == null) {
			log.warn("System has not been initialized!");
		}
		SystemParameter result = systemParameters.get(parameter.getCode());
		if (result == null) {
			log.debug("Adding new system parameter [" + parameter.getCode()
					+ "] value [" + parameter.getValue() + "]");
		} else {
			log.debug("Updating system parameter [" + parameter.getCode()
					+ "] from value [" + result.getValue() + "] to value ["
					+ parameter.getValue() + "].");
		}
		systemParameters.put(parameter.getCode(), parameter);
	}

	private MessageSource messageSource;

	private static final Map<String, SystemParameter> systemParameters = new Hashtable<String, SystemParameter>();

	private static final Map<String, SystemCode> systemCodes = new Hashtable<String, SystemCode>();

	/**
	 * 根据提供的系统代码,获取相应的系统代码实例
	 * 
	 * @param code
	 *            系统代码
	 * @return 系统代码实例
	 * @throws SystemRuntimeException
	 *             如果系统参数尚未被初始化过
	 * @throws SystemCodeNotFoundException
	 *             系统参数没有被找到
	 */
	public synchronized static SystemCode getCode(String code)
			throws SystemRuntimeException, SystemCodeNotFoundException {
		if (systemCodes == null) {
			log.error("System has not been initialized!");
			throw new SystemRuntimeException("System has not been initialized!");
		}
		SystemCode result = systemCodes.get(code);
		if (result == null)
			throw new SystemCodeNotFoundException();
		return result;
	}

	/**
	 * 根据提供的系统参数代码获取相应的系统参数
	 * 
	 * @param code
	 *            系统参数代码
	 * @return 系统参数
	 * @throws SystemRuntimeException
	 *             如果系统参数尚未被初始化过
	 * @throws SystemParameterNotFoundException
	 *             系统参数没有被找到
	 */
	public synchronized static SystemParameter getParameter(String code)
			throws SystemRuntimeException, SystemParameterNotFoundException {
		if (systemParameters == null) {
			log.error("System has not been initialized!");
			throw new SystemRuntimeException("System has not been initialized!");
		}
		SystemParameter result = systemParameters.get(code);
		if (result == null)
			throw new SystemParameterNotFoundException();
		return result;
	}

	/**
	 * @return the messageSource
	 */
	public MessageSource getMessageSource() {
		return messageSource;
	}

	/**
	 * @param messageSource
	 *            the messageSource to set
	 */
	public void setMessageSource(MessageSource messageSource) {
		this.messageSource = messageSource;
	}

}
